package view;

// <editor-fold defaultstate="collapsed" desc=" IMPORTS ">
import control.DetailedPanelListener;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumMap;
import java.util.EnumSet;
import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.text.JTextComponent;
import model.Cases;
import model.Cases.Field;
import model.Event;
import model.User;
import net.miginfocom.swing.MigLayout;
// </editor-fold>

/**
 * The class is responsible for displaying a form for case data.
 *
 * @author Tim
 * @version 2014-05-25
 */
public class DetailedPanel extends JPanel {

    private EnumMap<Cases.Field, Object> caseData;
    private ArrayList<EnumMap<Event.Field, Object>> eventList;
    private User.Type activeUserType;
    private EnumMap<User.Type, EnumSet> userRights;
    private EnumMap<Cases.Field, Collection> fieldChoices;
    private EnumMap<Cases.Field, Object> fields;
    private ActionListener actionListener;
    private JButton save;
    private JTable eventsTable;
    private JTextField commentField, fileField;
    private ArrayList<JButton> buttons;

    /**
     * Constructor for class DetailedPanel
     */
    public DetailedPanel() {
        this.caseData = new EnumMap<>(Cases.Field.class);
        this.eventList = new ArrayList<>();
        this.fields = new EnumMap<>(Cases.Field.class);
        this.buttons = new ArrayList<>();
        initPanel();
    }

    /**
     * Initializes the panel
     */
    private void initPanel() {
        // Adds some padding to the panel.
        this.setBorder(new javax.swing.border.EmptyBorder(10, 10, 10, 10));
        //this.setAlignmentY(TOP_ALIGNMENT);

        // Use MigLayout for this panel
        this.setLayout(new MigLayout());

        // Add left and right panel
        this.add(prepareLeftPanel());
        this.add(prepareRightPanel(), "h 100%");
    }

    /**
     * Prepares the left panel
     *
     * @return Jpanel leftPanel
     */
    private JPanel prepareLeftPanel() {
        JPanel leftPanel = new JPanel(new MigLayout());

        for (Cases.Field.Group fieldGroup : Cases.Field.Group.values()) {
            JPanel panel = new JPanel(new MigLayout());
            panel.setBorder(BorderFactory.createTitledBorder(fieldGroup.toString()));

            for (Cases.Field field : fieldGroup.getGroup()) {
                JLabel label = new JLabel(field.toString());
                panel.add(new JLabel(field.toString()), "w 130!");
                JComponent inputField;
                switch (field.getInputType()) {
                    case LONG_TEXT:
                        JTextArea textArea = new JTextArea(3, 30);
                        fields.put(field, textArea);
                        inputField = textArea;
                        break;
                    case LIST_CHOICE:
                        JComboBox comboBox = new JComboBox();
                        fields.put(field, comboBox);
                        inputField = comboBox;
                        break;
                    default:
                        JTextField textField = new JTextField(20);
                        fields.put(field, textField);
                        inputField = textField;
                }
                panel.add(inputField, "wrap");
            }
            leftPanel.add(panel, "wrap");
        }

        // Create buttons
        save = new JButton(DetailedPanelListener.Type.SAVE.toString());
        JButton cancel = new JButton(DetailedPanelListener.Type.CANCEL.toString());

        leftPanel.add(save, "split 2");
        leftPanel.add(cancel, "gapleft push");

        // Add buttons to ArrayList
        buttons.add(save);
        buttons.add(cancel);

        return leftPanel;
    }

    /**
     * Prepares the right panel
     *
     * @return JPanel rightPanel
     */
    private JPanel prepareRightPanel() {
        JPanel rightPanel = new JPanel(new MigLayout());
        rightPanel.setAlignmentY(TOP_ALIGNMENT);

        JPanel events = new JPanel(new MigLayout());
        events.setBorder(BorderFactory.createTitledBorder("Händelser"));

        // Creates a table.
        eventsTable = new JTable(new DefaultTableModel(Event.Field.values(), eventList.size()));

        eventsTable.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                if (e.getClickCount() == 2) {
                    ActionEvent event = new ActionEvent(e.getSource(), 0, DetailedPanelListener.Type.OPEN_FILE.toString());
                    actionListener.actionPerformed(event);
                }
            }
        });

        // Creates the form for Event data
        events.add(new JScrollPane(eventsTable), "span 2, wrap");

        JLabel commentLabel = new JLabel("Kommentar");
        events.add(commentLabel);
        commentField = new JTextField(20);
        events.add(commentField, "w 80%, wrap");

        JButton fileButton = new JButton(DetailedPanelListener.Type.ADD_FILE.toString());
        buttons.add(fileButton);
        events.add(fileButton);
        fileField = new JTextField(20);
        fileField.setEnabled(false);
        events.add(fileField, "w 80%, wrap");

        JButton addEvent = new JButton(DetailedPanelListener.Type.NEW_EVENT.toString());
        buttons.add(addEvent);
        events.add(addEvent, "skip 1, right");

        rightPanel.add(events);

        return rightPanel;
    }

    /**
     * Returns the data from the form.
     *
     * @return caseData
     */
    public EnumMap<Cases.Field, Object> getCaseData() {
        for (Cases.Field field : Cases.Field.values()) {
            switch (field.getInputType()) {
                case LIST_CHOICE:
                    JComboBox comboBox = (JComboBox) fields.get(field);
                    caseData.put(field, comboBox.getSelectedItem());
                    break;
                case LONG_TEXT:
                    JTextArea textArea = (JTextArea) fields.get(field);
                    caseData.put(field, textArea.getText());
                    break;
                default:
                    JTextField textField = (JTextField) fields.get(field);
                    caseData.put(field, textField.getText());
                    break;
            }
        }
        return caseData.clone();
    }

    /**
     * Returns the data from the event form.
     *
     * @return eventData
     */
    public EnumMap<Event.Field, JTextComponent> getEventData() {
        EnumMap<Event.Field, JTextComponent> eventData = new EnumMap<>(Event.Field.class);

        eventData.put(Event.Field.EVENT_DESCRIPTION, commentField);
        eventData.put(Event.Field.EVENT_FILE, fileField);

        return eventData;
    }

    /**
     * Updates the panel
     *
     * @param isNewCase Flag for new case
     * @param caseDataMap Case data
     * @param eventList A list containing all case events
     * @param activeUserType The type of the active user
     * @param fieldChoices Options for JComboBoxes
     * @param newCaseId The ID used for the next new case
     * @param userRights User rights for editing form fields
     */
    public void updatePanel(boolean isNewCase,
            EnumMap<Cases.Field, Object> caseDataMap,
            ArrayList<EnumMap<Event.Field, Object>> eventList,
            User.Type activeUserType,
            EnumMap<Cases.Field, Collection> fieldChoices,
            int newCaseId,
            EnumMap<User.Type, EnumSet> userRights) {

        if (isNewCase) {
            this.caseData = new EnumMap<>(Cases.Field.class);
            this.caseData.put(Cases.Field.CASE_ID, newCaseId);
        } else {
            this.caseData = caseDataMap;
        }
        this.eventList = eventList;
        this.activeUserType = activeUserType;
        this.fieldChoices = fieldChoices;
        this.userRights = userRights;

        for (Field field : fields.keySet()) {
            switch (field.getInputType()) {
                case LONG_TEXT:
                    JTextArea.class.cast(fields.get(field)).setText(caseData.get(field).toString());
                    break;
                case LIST_CHOICE:

                    // Fill JComboBox with options if available
                    if (fieldChoices.get(field) != null) {
                        DefaultComboBoxModel newModel = new DefaultComboBoxModel(fieldChoices.get(field).toArray());
                        JComboBox.class.cast(fields.get(field)).setModel(newModel);
                    } else {
                        JComboBox.class.cast(fields.get(field)).removeAllItems();
                    }

                    // Choose an option if data is available
                    if (caseData.get(field) != null) {
                        JComboBox.class.cast(fields.get(field)).setSelectedItem(caseData.get(field));
                    } else {
                        JComboBox.class.cast(fields.get(field)).setSelectedIndex(-1);
                    }
                    break;
                default:
                    if (caseData.get(field) != null) {
                        JTextField.class.cast(fields.get(field)).setText(caseData.get(field).toString());
                    } else {
                        JTextField.class.cast(fields.get(field)).setText("");
                    }
            }

            // Enable the field if the user has rights to edit it and disable it otherwise
            if (userRights.get(activeUserType).contains(field)) {
                JComponent.class.cast(fields.get(field)).setEnabled(true);
            } else {
                JComponent.class.cast(fields.get(field)).setEnabled(false);
            }
        }

        // Displays the right button depending on if it is new case or not
        if (isNewCase) {
            save.setText(DetailedPanelListener.Type.NEW_CASE.toString());
        } else {
            save.setText(DetailedPanelListener.Type.SAVE.toString());
        }

        updateEvents(eventList);
    }

    /**
     * Updates events
     *
     * @param eventList A list containing all case events
     */
    public void updateEvents(ArrayList<EnumMap<Event.Field, Object>> eventList) {
        eventsTable.setModel(new DefaultTableModel(Event.Field.values(), eventList.size()) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        }
        );
        for (int i = 0; i < eventList.size(); i++) {
            for (int j = 0; j < eventList.get(i).size(); j++) {

                EnumMap<Event.Field, Object> event = eventList.get(i);
                event.get(Event.Field.values()[j]);
                eventsTable.setValueAt(event.get(Event.Field.values()[j]), i, j);
            }
        }
    }

    /**
     * Adds a listener to buttons
     *
     * @param listener
     */
    public void addDetailedPanelListener(ActionListener listener) {
        actionListener = listener;
        for (JButton button : buttons) {
            button.addActionListener(listener);
        }
    }

    /**
     * Adds a file
     *
     * @param file Chosen file
     */
    public void addFile(File file) {
        fileField.setText(file.toString());
    }

    /**
     * Displays an error message
     */
    public void saveCaseMessage() {
        JOptionPane.showMessageDialog(null, "Ärendet sparat");
    }
}
